package com.example.demoappsocketserver;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.StrictMode;
import android.util.Log;

@SuppressLint("NewApi")
public class SocketServer implements Runnable {
    private String SOCKET_SERVER = "socket_server";
    //服务器端口
    private final int SERVER_PORT = 5111;
    //存储所有客户端Socket连接对象
    public List<Socket> mClientLists = new ArrayList<Socket>();
    public List<ClientSocketThread> mClientSocketThreads = new ArrayList<>();
    //线程池
    private ExecutorService mExecutorService;
    //ServerSocket对象
    private ServerSocket mServerSocket;
    private PrintWriter mPrintWriter;
    private OnServerListener mOnServerListener;

    public static final int SEND_DATA = 0x0001;
    private static String MSG_CLIENT_IP = "client_ip";
    private static String MSG_CLIENT_PORT = "client_port";
    private static String MSG_DATA = "data";

    public SocketServer() {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
        startServer();
    }

    //接收线程发送过来信息，并用TextView显示
    public Handler mHandler = new Handler(Looper.getMainLooper()) {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case SEND_DATA:
                    String clienIp = msg.getData().getString(MSG_CLIENT_IP);
                    int clientPort = msg.getData().getInt(MSG_CLIENT_PORT);
                    String data = msg.getData().getString(MSG_DATA);
                    Log.d(SOCKET_SERVER, "客户端Ip: " + clienIp + "\t客户端Port: " + clientPort + "\t数据： " + data);
                    if (mOnServerListener != null) {
                        mOnServerListener.onReceiveData(clienIp, clientPort, data);
                    }
                    break;
                default:
                    break;
            }
        }
    };

    /**
     * 开启服务
     */
    public void startServer() {
        try {
            if (mServerSocket != null) {
                mServerSocket.close();
            }
            //设置服务器端口
            mServerSocket = new ServerSocket(SERVER_PORT);
            //创建一个线程池
            mExecutorService = Executors.newCachedThreadPool();
            //用来临时保存客户端连接的Socket对象
            new Thread(SocketServer.this).start();
        } catch (IOException e) {
            Log.e(SOCKET_SERVER, e.toString());
        }

    }


    @Override
    public void run() {
        Socket client = null;
        ClientSocketThread clientSocketThread = null;
        try {
            while (true) {
                //接收客户连接并添加到list中
                if (!mServerSocket.isClosed()) {
                    client = mServerSocket.accept();
                    Log.d(SOCKET_SERVER, "收到客户端连接。。。客户端IP: " + client.getInetAddress() + "\t" + "客户端Port: " + client.getLocalPort());
                    mClientLists.add(client);
                    //开启一个客户端线程
                    if (client != null) {
                        //异常捕不到，客户端退出后，程序挂了
                        clientSocketThread = new ClientSocketThread(client);
                        mClientSocketThreads.add(clientSocketThread);
                        mExecutorService.execute(clientSocketThread);
                    }
                } else {
                    if (mOnServerListener != null) {
                        mOnServerListener.onServerState(mServerSocket.isClosed());
                    }
                }
            }
        } catch (Exception e) {
            mClientLists.remove(client);
            if (clientSocketThread != null) {
                mClientSocketThreads.remove(clientSocketThread);
            }
            Log.e(SOCKET_SERVER, e.toString());
            if(client != null){
                Log.d(SOCKET_SERVER, "客户端Ip: " + client.getInetAddress().toString() + "\t客户端Port: " + client.getLocalPort() + "\t" + OnServerListener.MSG_DISCONNECT);
                if (mOnServerListener != null) {
                    mOnServerListener.onClientConnectState(client.getInetAddress().toString(), client.getLocalPort(), OnServerListener.DISCONNECT, OnServerListener.MSG_DISCONNECT);
                }
            }

        }
    }

    /**
     * 向客户端发送消息
     *
     * @param data
     */
    public void sendData(String data) {
        try {
            if (mClientLists.size() > 0) {
                for (Socket client : mClientLists) {
                    mPrintWriter = new PrintWriter(client.getOutputStream(), true);
                    mPrintWriter.println(data);
                    Log.d(SOCKET_SERVER, "MSG to Client: " + data);
                }
            }
        } catch (Exception e) {
            Log.e("向客户端发送消息败了", e.toString());
            startServer();//消息发送失败，重启服务器
        }
    }


    public void closeServer() {
        try {
            mServerSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 每个客户端单独开启一个线程
     */
    class ClientSocketThread implements Runnable {
        private Socket mSocket;
        private DataInputStream dinput;

        public ClientSocketThread(Socket socket) {
            try {
                this.mSocket = socket;
                dinput = new DataInputStream(socket.getInputStream());
                if (mSocket.isConnected()) {
                    sendData("from server...你已经成功连接服务器");
                    Log.d(SOCKET_SERVER, "客户端Ip: " + mSocket.getInetAddress().toString() + "\t客户端Port: " + mSocket.getLocalPort() + "\t" + OnServerListener.MSG_CONNECT_SUCESS);
                    if (mOnServerListener != null) {
                        mOnServerListener.onClientConnectState(mSocket.getInetAddress().toString(), mSocket.getLocalPort(), OnServerListener.CONNECTED, OnServerListener.MSG_CONNECT_SUCESS);
                    }
                } else {
                    Log.d(SOCKET_SERVER, "客户端Ip: " + mSocket.getInetAddress().toString() + "\t客户端Port: " + mSocket.getLocalPort() + "\t" + OnServerListener.MSG_DISCONNECT);
                    if (mOnServerListener != null) {
                        mOnServerListener.onClientConnectState(mSocket.getInetAddress().toString(), mSocket.getLocalPort(), OnServerListener.DISCONNECT, OnServerListener.MSG_DISCONNECT);
                    }
                }
            } catch (Exception e) {
                Log.e(SOCKET_SERVER, e.toString());
            }

        }

        @Override
        public void run() {
            try {
                if (!mSocket.isClosed()) {
                    if (mSocket.isConnected()) {
                        if (!mSocket.isInputShutdown()) {
                            InputStream inputStream = mSocket.getInputStream();
                            if (inputStream != null) {
                                byte[] buffer = new byte[1024];
                                int len = -1;
                                //读取数据
                                while ((len = inputStream.read(buffer)) != -1) {
                                    String data = new String(buffer, 0, len);
                                    Message message = new Message();
                                    message.what = SEND_DATA;
                                    Bundle bundle = new Bundle();
                                    bundle.putString(MSG_CLIENT_IP, mSocket.getInetAddress().toString());
                                    bundle.putInt(MSG_CLIENT_PORT, mSocket.getLocalPort());
                                    bundle.putString(MSG_DATA, data);
                                    message.setData(bundle);
                                    mHandler.sendMessage(message);
                                }
                            }


                        }
                    }
                }

            } catch (IOException e) {
                Log.e(SOCKET_SERVER, e.toString());
            }
        }
    }


    public interface OnServerListener {

        int CONNECTED = 0;
        int DISCONNECT = 1;
        String MSG_CONNECT_SUCESS = "连接成功";
        String MSG_DISCONNECT = "断开连接";


        /**
         * @param isStarted
         */
        void onServerState(boolean isStarted);

        /**
         * 客户端连接状态
         */
        void onClientConnectState(String clientIp, int clientPort, int state, String msg);

        /**
         * 接收数据
         *
         * @param data 接收的数据
         */
        void onReceiveData(String fromClientIp, int fromClientPort, String data);

    }


    public void setOnServerListener(OnServerListener onServerListener) {
        mOnServerListener = onServerListener;
    }

}